
package at.fhj.ase.crypto.client.net;

import java.io.IOException;
import java.net.Socket;

import at.fhj.ase.crypto.common.net.MessageHandler;
import at.fhj.ase.crypto.common.net.SocketWrapperThread;

/**
 * Class mainly exists for convenience and easier understanding reasons<br>
 * It represents a connection from this client <strong>to</strong> server.<br>
 * <p>
 * We could also say that the class is another "wrapper" for the {@link SocketWrapperThread} as it automatically instantiates the thread and also starts it.<br>
 * But the main reason is for easier understanding as a {@link SocketWrapperThread} can (and should!) be used on both client and server side, and no body really
 * knows which socket is meant then (can be a client as well as a server socket, concerning the direction).
 * <p>
 * Using this class, it should be clear that a connection from client to server is created, using a {@link SocketWrapperThread} in the background.<br>
 * As we are only allowed to establish one socket connection to the server, this class is implemented as a singleton pattern.
 * 
 * @author sfe | www.fh-joanneum.at | Practical Aspects of Cryptography
 */
class ClientServerConnection {
  /** The sole (singleton) instance of this class */
  private static ClientServerConnection INSTANCE;
  /** Saving an instance of the created {@link SocketWrapperThread} (e.g. to be able to stop it again from outside) */
  private final SocketWrapperThread socketWrapper;

  /**
   * Creating the sole instance of this application wrapping the provided {@link Socket} instance being connected by the provided {@link ServerConnector}.
   * 
   * @param socket the socket connection that shall be encapsulated by this class
   * @param serverConnector the {@link ServerConnector} that creates and uses this instance
   * @return the sole connection to the server, wrapped by this instance
   * @throws IOException if there is an error at creating a {@link ClientServerConnection}
   */
  static ClientServerConnection create(Socket socket, ServerConnector serverConnector) throws IOException {
    if (INSTANCE == null) {
      INSTANCE = new ClientServerConnection(socket, serverConnector);
    }
    return INSTANCE;
  }

  /**
   * Constructor creating and establishing a connection from client to server.<br>
   * An encapsulated {@link SocketWrapperThread} is therefore created and also started.
   * 
   * @param socket the socket we want to wrap
   * @param messageHandler the {@link MessageHandler} that is needed by the encapsulated {@link SocketWrapperThread} instance
   * @throws IOException if a problem occurs while creating the {@link SocketWrapperThread}
   */
  private ClientServerConnection(Socket socket, ServerConnector serverConnector) throws IOException {
    socketWrapper = new SocketWrapperThread(socket, serverConnector);
    socketWrapper.start();
  }

  /** @return the instance of the running {@link SocketWrapperThread} (e.g. for stopping it again from outside) */
  final SocketWrapperThread getSocketWrapper() {
    return socketWrapper;
  }
}
